;============================================================================
;
; FILE: KEYBOARD.ASM
; BY:   CSC
; DATE: AUG 06, 96
; ------------------
;
; REVISION HISTORY:
;
; Kelly & SMR [Aug 06, 96]/@RSCL/: reset_clock0() function added
;
;============================================================================


;.386p
P486
SMART
MODEL FLAT

;-------------------MOUSE TYPES--------------------------------------------
MOUSE_UNK      EQU   00h
MOUSE_PS2      EQU   02h
;-------------------Ports--------------------------------------------
MAKE_CODE      EQU   128; or less
;-------------------Ports--------------------------------------------
KEYBOARD_PORT  EQU   60h
;--------------------------------------------------------------------

;_DATA SEGMENT DWORD PUBLIC 'DATA'
.DATA

;-------------------INTERUPT VARIABLES-------------------------
sav_DS                  dw 1 dup (0)   ;Save ds for this code
sav_KEYBOARDINT_seg     dd 1 dup (0)   ;segment of 09 interupt.
sav_KEYBOARDINT_ofs     dd 1 dup (0)   ;offset of 09 interupt.
;--------------------------------------------------------------

;-------------------GENERAL VARIABLES-------------------------
branchreg     DB 1 dup (0) ;Branch flag register
i_active      DB 1 dup (0) ;Flag for telling if the interupt handler 
;--------------------------------------------------------------

;------------------GLOBAL VARIABLES---------------------------
 _g_keypressed    DB 1 dup (0) 
;--------------------------------------------------------------
;_DATA	ENDS

;_TEXT SEGMENT BYTE PUBLIC 'CODE'
.CODE

;ASSUME	cs:_TEXT, ds:_DATA

;-------------------EXTERNAL JUNK------------------------------
PUBLIC reset_clock0_

PUBLIC _g_keypressed
PUBLIC FWKeyboard_Driver_
PUBLIC FWKeyboard_ClearBuffer_
PUBLIC FWKeyboard_InstallDriver_
PUBLIC FWKeyboard_DestallDriver_

;--------------------------------------------------------+
; Keyboard driver to use with normal serial mouse
;--------------------------------------------------------+


FWKeyboard_Driver_ proc
        push ds            ;These two top things are dummys
        push es            ;used to store return address to real interupt
                           ;code.
	push ds
	push es
	push eax

	mov ax,cs
	mov ds,ax
	mov ds,sav_DS
	mov es,sav_DS

	mov eax,sav_KEYBOARDINT_ofs
	mov es, sav_KEYBOARDINT_seg
	mov [esp + 0Ch],eax
	mov [esp + 10h],es

	cmp i_active,0     ;Don't do anything unless the previous key
	jne leave_driver   ;has been dealt with.

	cmp _g_keypressed,0;Don't do anything unless the previous key
	jne leave_driver   ;has been dealt with.

driver_active:
	mov i_active,1     ;Driver is now active

	in al,KEYBOARD_PORT
	cmp al,MAKE_CODE
        jl  leave_driver   ;To qualify, a key must have been pressed and
                           ;released

        sub al,128
        cmp al,96          ;there was an 'extended' key hit, value follows.
        je leave_driver    ;go back through for 'extended' key value.

	mov _g_keypressed,al

 leave_driver:
	mov i_active,0
	pop eax
	pop es
    pop ds
	retf
FWKeyboard_Driver_ endp

;--------------------------------------------------------+
; The driver for the fucking PS/2 mouse bug
;--------------------------------------------------------+
FWKeyboard_DriverPS2_ proc
    cli
	push ds
	push es
	push eax

	mov ax,cs
	mov ds,ax
	mov ds,sav_DS
	mov es,sav_DS

    ;Set up a place for the keyboard driver to return to
	mov eax,[esp + 14h]
	push eax
	push cs
	mov eax, offset start_keyboard_drv
	push eax

   ;Set up the call to the keyboard driver
	mov eax,sav_KEYBOARDINT_ofs
	mov es, sav_KEYBOARDINT_seg
	push es
	push eax
	;Execute the keyboard driver by returning to it.
	retf

start_keyboard_drv:
     ;cli
        cmp i_active,0       ;Don't do anything unless the previous key
        jne leave_ps2driver  ;has been dealt with.

        cmp _g_keypressed,0  ;Don't do anything unless the previous key
        jne leave_ps2driver  ;has been dealt with.

ps2driver_active:
        mov i_active,1       ;Driver is now active

	in al,KEYBOARD_PORT
	cmp al,MAKE_CODE
        jl  leave_ps2driver  ;To qualify, a key must have been pressed and
                             ;released

    sub al,128
        cmp al,96            ;there was an 'extended' key hit, value follows.
        je leave_ps2driver   ;go back through for 'extended' key value.

	mov _g_keypressed,al

 leave_ps2driver:
	mov i_active,0
	pop eax
	pop es
    pop ds
	sti
	iret
	;retf
FWKeyboard_DriverPS2_ endp

;--------------------------------------------------------+
;  Gets the location of interupt 09, (keyboard interupt).
;--------------------------------------------------------+

FWKeyboard_get_09_info proc
     push es
     push eax
     push ebx

	 mov ax,3509h                  ;Set up to get int 09 loc
	 int 21h                       ;Get it

	 mov ax,es                     ;Twiddle es to 32 bits
	 movzx eax,ax

	 mov dword ptr sav_KEYBOARDINT_seg,eax  ;Save the information
	 mov dword ptr sav_KEYBOARDINT_ofs,ebx  
	 mov  word ptr sav_DS,ds       ;Save ds

	 pop  ebx
	 pop  eax
	 pop  es
	 ret
FWKeyboard_get_09_info endp

;-----------------------------------------------------------+
;  FWKeyboard_InstallDriver(char mousetype)
;
;  Resets the location of interupt 09, the keyboard interupt.
;-----------------------------------------------------------+

FWKeyboard_InstallDriver_ proc
;eax,edx,ebx,ecx 
     push ds
     push eax
     push ecx
     push edx

     call FWKeyboard_get_09_info 

     ;Now reset the interupt.
     mov cx,cs
	 mov ds,cx

	 cmp eax, MOUSE_PS2
	 jne normal_keyboard_drv 
ps2_keyboard_drv:
	 mov edx, offset FWKeyboard_DriverPS2_
	 jmp install_kbdriver

normal_keyboard_drv:
	 mov edx, offset FWKeyboard_Driver_

install_kbdriver:
     mov ax,2509h
	 int 21h

	 pop  edx
	 pop  ecx
	 pop  eax
	 pop  ds
	 ret
FWKeyboard_InstallDriver_ endp

;-----------------------------------------------------------+
;  FWKeyboard_DestallDriver()
;
;  Resets the location of interupt 09, the keyboard interupt
;  back to its original value
;-----------------------------------------------------------+

FWKeyboard_DestallDriver_ proc
     cli 
     push ds
     push eax
     push edx
	 
     mov edx, sav_KEYBOARDINT_ofs
     mov ds,  sav_KEYBOARDINT_seg
     mov ax,2509h
	 sti
	 int 21h

	 pop  edx
	 pop  eax
	 pop  ds
	 ret

FWKeyboard_DestallDriver_ endp


;---------------------------+
; Clears Keyboard buffer
;---------------------------+

FWKeyboard_ClearBuffer_ proc
 push ax
 mov  ah,01h
 int  16h
 jz   do_nothing
 mov  ah,00
 int  16h

do_nothing:
 pop  ax
 ret
FWKeyboard_ClearBuffer_ endp


;---------------------------+
; Clock reset call /@RSCL/
;---------------------------+

reset_clock0_ proc

      push ax

         mov al,36h
         out 43h,al
         mov al,0
         out 40h,al
         out 40h,al

      pop ax
      ret

reset_clock0_ endp

;_TEXT ENDS
END

